""" Main Graphical UI """

# System includes
import logging

# Platform includes
import pygame
from pygame.locals import *

# Engine includes
from pgEngine import game, point

# UI includes
from mapWindow import MapWindow
from mapMode import MapMode
from editMode import EditMode
from colors import *
from resources import Resources

class MainWindow:
    # Us
    screen = None
    width = None
    height = None
    screenSize = None
    background = None

    # Tick-tock
    clock = None
    curT = 0

    # Subwindows and overlays
    overlays = None
    overlayRects = None
    tabs = None
    curTab = None
    map = None
    mappos = None
    mapSize = None
    dialog = None
    dialogCount = 0
    
    # Fonts
    font = None
    menuFont = None

    # Sizes
    spacing = 0
    menuW = 146
    statusH = 210
    dialogH = 75
    dialogIH = 48
    tabsH = 40
    tabsIH = 16
    tabsW = 370
        
    # Input modes
    mode = None
    modes = None
    
    # Mouse location
    mouseY = 0
    mouseX = 0
    
    # Other objects
    game = None
    res = None
    
    # Logging
    logger = logging.getLogger("pgame.gui.mainWindow")
    
    def __init__(self, width=1024, height=768, gameObj=None, resources=None):
        pygame.init()
        self.width = width
        self.height = height
        self.screenSize = point.Point(width, height)
        self.screen = pygame.display.set_mode(self.screenSize.pos, RESIZABLE)
        pygame.key.set_repeat(150, 8)
        pygame.display.set_caption("Arrr!")
        self.clock = pygame.time.Clock()
        if gameObj is None:
            gameObj = game.PirateGame()
        if resources is None:
            resources = Resources()
        self.res = resources
        self.game = gameObj
        self.tabs = []
        self.mode = []
        self.modes = {}
        self.curTab = None
        self.map = None
        self.tabNames = [ "Map", "Editor", "Ship", "Crew",
                          "Port", "Enemy", "Creature" ]
        self.tabSCK = [ K_m, K_e, K_s, K_c, K_p, K_n, K_r ]
        self.overlays = {}
        self.overlayRects = {}
        
    def checkOverlayClick(self, xy, ovly=None):
        if ovly is None:
            for k, rcOvly in self.overlayRects.items():
                if rcOvly.collidepoint(xy) and k != "map":
                    if self.curTab[0] != "Editor" and k in ("menu","menuBar"):
                        continue
                    return False
            return True
        
        return self.overlayRects[ovly].collidepoint(xy)
        
    def createBackground(self):
        bgr = pygame.Surface(self.screenSize.pos, RLEACCEL|SRCALPHA, 32)

        # Menu/Status border
        self.drawOverlay("status", bgr)
        self.drawOverlay("menu", bgr)
        
        # Dialog border
        self.drawOverlay("dialog", bgr)

        # Map border
        
        # Tabs border
        self.drawOverlay("tabsBorder", bgr)

        self.background = bgr

        
    def createWidgets(self):
        # Load the fonts
        self.font = self.res.loadFont("VeraMono.ttf", 12)
        self.menuFont = self.res.loadFont("Chanticleer.ttf", 14)
            
        # Do some sizing
        self.resizeWidgets()
        
        # Create the map window
        self.mappos = point.Point(132.0, -90.0)
        self.map = MapWindow(self.overlayRects["map"], self.res, self)
        
        # Create some dialog messages.
        self.dialogCount = 0
        self.dialog = []
        # TODO: Create some maximum and start recycling.

    def createOverlay(self, name, width, height, sep=()):
        self.overlays[name] = self.res.renderDialog(width, height, sep)
        return self.overlays[name]
    
    def createOvlyRect(self, name, x, y, w, h):
        self.overlayRects[name] = pygame.Rect(x,y,w,h)
        return self.overlayRects[name]
        
    def resizeWidgets(self):
        self.mapSize = self.screenSize = point.Point(self.width, self.height)
        
        self.screen = pygame.display.set_mode(self.screenSize.pos,
                                              RESIZABLE|HWSURFACE)
        
        
        # Menu and status bar
        rcMenuBar = self.createOvlyRect("menuBar", 0, 0,
                                        self.menuW, self.height)
        rcStatus = self.createOvlyRect("status", rcMenuBar.left, rcMenuBar.top,
                                        self.menuW, self.statusH)
        rcMenu = self.createOvlyRect("menu", rcStatus.left,
                                             rcStatus.bottom - 1,
                                             self.menuW,
                                             self.height - self.statusH + 1)
                                         
        self.createOverlay("menu", rcMenu.width, rcMenu.height)
        
        self.createOverlay("editMenu", rcMenu.width,
                                       rcMenu.height,
                                      (rcMenu.height - 79,))
        self.createOverlay("status", rcStatus.width, rcStatus.height)
        
        
        # Dialog messages
        rcDialog = self.createOvlyRect("dialog",
                                       self.width-self.tabsW - 15,
                                       self.height-self.dialogH-15,
                                       self.tabsW,
                                       self.dialogH)

        self.createOverlay("dialog", rcDialog.width, rcDialog.height)
        
        # Tabs
        rcTabs = self.createOvlyRect("tabs", self.width - self.tabsW - 15,
                                             16, self.tabsW, self.tabsH - 20)
        rcTabsBorder = rcTabs.inflate(32,20)
        topleft = rcTabsBorder.topleft
        size = rcTabsBorder.size
        self.createOvlyRect("tabsBorder", *(topleft + size))
        
        self.createOverlay("tabsBorder", rcTabsBorder.width,
                                         rcTabsBorder.height)
        
        left, top = rcTabs.topleft
        height = rcTabs.height
        if len(self.tabs) == 0:
            # Create the tabs
            for tab in self.tabNames:
                self.tabs.append([])
                self.tabs[-1] = [tab,
                                 self.menuFont.render(tab, 1, (85,125,165)),
                                 self.menuFont.render(tab, 1, btgrey)]
                tabwidth = self.tabs[-1][1].get_width() + 20
                self.tabs[-1].append(pygame.Rect(left, top, tabwidth, height))
                left += tabwidth
        else:
            for tab in range(len(self.tabNames)):
                tabwidth = self.tabs[tab][1].get_width() + 20
                self.tabs[tab][3] = pygame.Rect(left, top, tabwidth, height)
                left += tabwidth

        # And finally, the map.
        self.createOvlyRect("map", 0, 0, self.mapSize.x, self.mapSize.y)

        if self.map:
            self.map.resize(self.overlayRects["map"])
        
        self.createBackground()
        
    
    def drawWidgets(self):
        self.modeDispatch("draw" + self.curTab[0])
        #self.screen.blit(self.background, (0, 0))
        self.modeDispatch("drawStatus")
        self.modeDispatch("drawMenu")
        self.drawDialog()
        self.drawTabs()
        
        
    def drawTabs(self):
        self.drawOverlay("tabsBorder")
        rcTabs = self.overlayRects["tabs"]
        left = rcTabs.left
        top = rcTabs.top
        
        for tab in self.tabs:
            tabWidth = tab[1].get_width() + 20
            if tab == self.curTab:
                rcTab = pygame.Rect(left, top, tabWidth, self.tabsIH)
                self.screen.fill((240,240,240), rcTab)
                self.screen.blit(tab[1], (left+10, top))
            else:
                self.screen.blit(tab[2], (left+10, top))
            left += tabWidth
    
    def dialogMessage(self, message):
        self.dialog.append(message)
        
    def drawStatusLine(self, left, top, text):
        self.screen.blit(text, (left, top))
        return top + 15
    
    def drawOverlay(self, name, onto=None, rcName=None):
        if onto is None:
            onto = self.screen
        if rcName is None:
            rcName = name
        rcOverlay = self.overlayRects[rcName]
        bgrOverlay = self.overlays[name]
        onto.blit(bgrOverlay, rcOverlay)
        return rcOverlay
    
    def drawStatus(self):
        rcStatus = self.drawOverlay("status")
        
        left = rcStatus.left + 14
        top = rcStatus.top + 15
        
        locX = self.font.render(" ScreenX: %i" % self.mouseX, 1, white)
        top = self.drawStatusLine(left, top, locX)
        locY = self.font.render(" ScreenY: %i" % self.mouseY, 1, white)
        top = self.drawStatusLine(left, top, locY)

        if self.curTab[0] == "Editor":
            scrposX, scrposY = self.map.getMousePos(screen=False,grid=False)
        else:
            scrposX, scrposY = self.map.getMousePos(screen=False)

        locX = self.font.render("MapCellX: %0.2f" % scrposX, 1, white)
        top = self.drawStatusLine(left, top, locX)
        locY = self.font.render("MapCellY: %0.2f" % scrposY, 1, white)
        top = self.drawStatusLine(left, top, locY)
        
        locX = self.font.render(" MapPosX: %0.2f" % self.mappos.x, 1, white)
        top = self.drawStatusLine(left, top, locX)
        locY = self.font.render(" MapPosY: %0.2f" % self.mappos.y, 1, white)
        top = self.drawStatusLine(left, top, locY)

        curTurn = self.font.render("    Turn: %i" % self.game.turn, 1, white)
        top = self.drawStatusLine(left, top, curTurn)


    def drawDialog(self):
        rcDialog = self.drawOverlay("dialog")
        if self.dialogCount < len(self.dialog):
            for n in range(self.dialogCount, len(self.dialog)):
                self.dialog[n] = self.font.render(self.dialog[n], True, white)
            self.dialogCount = len(self.dialog)
        top = rcDialog.top + (self.dialogH - self.dialogIH) / 2
        for n in range(-1, -self.dialogCount, -1):
            self.screen.blit(self.dialog[n], (rcDialog.left + 20, top))
            height = self.dialog[n].get_height()
            if top > rcDialog.bottom - height * 3 - 1:
                break
            top += height
        
    def modeDispatch(self, hdlrName, *args):
        for nhdlr in range(-1, -len(self.mode)-1, -1):
            if nhdlr < -len(self.mode):
                continue
            mode = self.mode[nhdlr]
            if hasattr(mode, hdlrName):
                fnHandler = getattr(mode, hdlrName)
                retVal = fnHandler(*args)
                if retVal is not None:
                    return retVal
    
    def switchTab(self, tab):
        if tab != self.curTab and tab[0] in self.modes:
            if self.curTab:
                self.modes[self.curTab[0]] = self.mode
            self.curTab = tab
            self.mode = self.modes[self.curTab[0]]

    def onEvent(self, event):
        if event.type == VIDEORESIZE:
            self.screenSize = point.Point(event.w, event.h)
            self.width = event.w
            self.height = event.h
            self.resizeWidgets()

        elif event.type == QUIT:
            return True

        elif event.type == KEYDOWN:
            if event.key == K_ESCAPE:
                return True
            elif event.key in self.tabSCK and event.mod & KMOD_ALT:
                nIndex = self.tabSCK.index(event.key)
                tab = self.tabs[nIndex]
                self.switchTab(tab)
                return False
                

        elif (event.type == MOUSEBUTTONDOWN and
              self.checkOverlayClick(event.pos, "tabsBorder") and
              event.button == 1):
            # Check the tabs
            for tab in self.tabs:
                if tab[3].collidepoint(event.pos):
                    self.switchTab(tab)
                    return False
            
        return False
        

    def run(self):
        self.createWidgets()
        self.map.createTiles()
        self.mode = []
        self.modes["Map"] = [self, MapMode(self.game, self)]
        self.modes["Map"].extend(self.mode)
        self.mode = []
        self.modes["Editor"] = [self, EditMode(self.game, self)]
        self.modes["Editor"].extend(self.mode)
        self.mode = []
        self.switchTab(self.tabs[0])
        self.curT = 0
        
        while 1:
            self.clock.tick(20)
            if self.game.state == self.game.PRE_TURN:
                self.game.tick(self.curT)
                # Display the weather.
                self.dialogMessage("Wind: %s" % str(self.game.weather))
            else:
                self.game.tick(self.curT)
                
            if self.game.state == self.game.PRE_TURN:
                self.map.dirty = True
                
            
            (self.mouseX, self.mouseY) = pygame.mouse.get_pos()
    
            #Handle Input Events
            for event in pygame.event.get():
                doQuit = self.modeDispatch("onEvent", event)
                if doQuit:
                    return
    
            #Draw Everything
            if pygame.display.get_active():
                self.drawWidgets()
                pygame.display.flip()
            self.curT += 1


